home *** CD-ROM | disk | FTP | other *** search
/ GFX Sensations 1 / Graphic Sensations - Volume 1.iso / tools / amiga / 3d_tools / irit40s.lha / Irit / cagd_lib / bsp2poly.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-12-30  |  17.1 KB  |  521 lines

  1. /******************************************************************************
  2. * Bsp2Poly.c - Bezier to polygon/polylines conversion routines.              *
  3. *******************************************************************************
  4. * Written by Gershon Elber, Mar. 90.                          *
  5. ******************************************************************************/
  6.  
  7. #include "cagd_loc.h"
  8.  
  9. static CagdPolygonStruct *BspC1Srf2Polygons(CagdSrfStruct *Srf, int FineNess,
  10.      CagdBType ComputeNormals, CagdBType FourPerFlat, CagdBType ComputeUV);
  11.  
  12. /*****************************************************************************
  13. * Routine to convert a single bspline surface to set of triangles         *
  14. * approximating it. FineNess is a finess control on result and the bigger it *
  15. * is more triangles may result. a value of 10 is a good start value.         *
  16. * NULL is returned in case of an error, otherwise list of CagdPolygonStruct. *
  17. *   This routine looks for C1 discontinuities in the surface and split it    *
  18. * into C1 continuous patches to invoke BspC1Srf2Polygons to gen. polygons.   *
  19. *****************************************************************************/
  20. CagdPolygonStruct *BspSrf2Polygons(CagdSrfStruct *Srf, int FineNess,
  21.      CagdBType ComputeNormals, CagdBType FourPerFlat, CagdBType ComputeUV)
  22. {
  23.     CagdRType u, v;
  24.     int UOrder = Srf -> UOrder,
  25.     VOrder = Srf -> VOrder,
  26.     ULength = Srf -> ULength,
  27.     VLength = Srf -> VLength;
  28.     CagdBType
  29.     HasUDiscont = BspKnotC1Discont(Srf -> UKnotVector, UOrder,
  30.                        ULength, &u),
  31.     HasVDiscont = BspKnotC1Discont(Srf -> VKnotVector, VOrder,
  32.                        VLength, &v);
  33.     CagdPolygonStruct *Poly;
  34.  
  35.     if (HasUDiscont || HasVDiscont) {
  36.     CagdSrfStruct
  37.         *Srf1 = HasUDiscont ? BspSrfSubdivAtParam(Srf, u,
  38.                               CAGD_CONST_U_DIR)
  39.                 : BspSrfSubdivAtParam(Srf, v,
  40.                               CAGD_CONST_V_DIR),
  41.         *Srf2 = Srf1 -> Pnext;
  42.     CagdPolygonStruct
  43.         *Poly1 = BspSrf2Polygons(Srf1, FineNess,
  44.                      ComputeNormals, FourPerFlat, ComputeUV),
  45.         *Poly2 = BspSrf2Polygons(Srf2, FineNess,
  46.                      ComputeNormals, FourPerFlat, ComputeUV);
  47.  
  48.     CagdSrfFreeList(Srf1);
  49.  
  50.     /* Chain the two lists together: */
  51.     for (Poly = Poly1; Poly -> Pnext != NULL; Poly = Poly -> Pnext);
  52.     Poly -> Pnext = Poly2;
  53.     Poly = Poly1;
  54.     }
  55.     else
  56.     Poly = BspC1Srf2Polygons(Srf, FineNess, ComputeNormals, FourPerFlat,
  57.                                  ComputeUV);
  58.  
  59.     return Poly;
  60. }
  61.  
  62. /*****************************************************************************
  63. * Routine to convert a single C1 continuouse bspline srf to set of triangles *
  64. * approximating it. FineNess is a finess control on result and the bigger it *
  65. * is more triangles may result. a value of 10 is a good start value.         *
  66. * NULL is returned in case of an error, otherwise list of CagdPolygonStruct. *
  67. *****************************************************************************/
  68. static CagdPolygonStruct *BspC1Srf2Polygons(CagdSrfStruct *Srf, int FineNess,
  69.      CagdBType ComputeNormals, CagdBType FourPerFlat, CagdBType ComputeUV)
  70. {
  71.     int i, j, FineNessU1, FineNessV1, FineNessU, FineNessV, BaseIndex;
  72.     CagdRType u, v, UMin, UMax, VMin, VMax, *Pt;
  73.     CagdPointType
  74.     PType = Srf -> PType;
  75.     CagdPtStruct PtCenter, *Pt1, *Pt2, *Pt3, *Pt4, *PtMesh, *PtMeshPtr;
  76.     CagdUVStruct UVCenter, *UVMeshPtr,
  77.     *UV1 = NULL,
  78.     *UV2 = NULL,
  79.     *UV3 = NULL,
  80.     *UV4 = NULL,
  81.     *UVMesh = NULL;
  82.     CagdVecStruct NlCenter,
  83.     *Nl1 = NULL,
  84.     *Nl2 = NULL,
  85.     *Nl3 = NULL,
  86.     *Nl4 = NULL,
  87.     *PtNrml = NULL;
  88.     CagdCrvStruct *Crv;
  89.     CagdPolygonStruct *Poly,
  90.     *PolyHead = NULL;
  91.  
  92.     if (!CAGD_IS_BSPLINE_SRF(Srf))
  93.     return NULL;
  94.  
  95.     /* Simple heuristic to estimate how many samples to compute. */
  96.     FineNessU = Srf -> ULength * FineNess / 10;
  97.     FineNessV = Srf -> VLength * FineNess / 10;
  98.  
  99.     if (FineNessU < 2)
  100.     FineNessU = 2;
  101.     if (FineNessV < 2)
  102.     FineNessV = 2;
  103.     switch (_CagdLin2Poly) {
  104.     case CAGD_REG_POLY_PER_LIN:
  105.         break;
  106.         case CAGD_ONE_POLY_PER_LIN:
  107.         if (Srf -> UOrder == 2)
  108.         FineNessU = 2;
  109.         if (Srf -> VOrder == 2)
  110.         FineNessV = 2;
  111.         break;
  112.         case CAGD_ONE_POLY_PER_COLIN:
  113.         break;
  114.     }
  115.     FineNessU1 = FineNessU - 1;
  116.     FineNessV1 = FineNessV - 1;
  117.  
  118.     /* Current to surface property such as curvature is used as subdivison   */
  119.     /* criterion and the surface is subdivided, equally spaced in parametric */
  120.     /* space, using FineNess as number of subdivisions per axis.         */
  121.  
  122.     /* Allocate a mesh to hold all vertices so common vertices need not be   */
  123.     /* Evaluated twice, and evaluate the surface at these mesh points.         */
  124.     PtMeshPtr = PtMesh = (CagdPtStruct *) IritMalloc(FineNessU * FineNessV *
  125.                             sizeof(CagdPtStruct));
  126.     if (ComputeUV) {
  127.     UVMeshPtr = UVMesh = (CagdUVStruct *)
  128.         IritMalloc(FineNessU * FineNessV * sizeof(CagdUVStruct));
  129.     }
  130.  
  131.     BspSrfDomain(Srf, &UMin, &UMax, &VMin, &VMax);
  132.  
  133.     for (i = 0; i < FineNessU; i++) {
  134.     u = UMin + (UMax - UMin) * i / ((CagdRType) FineNessU1);
  135.     Crv = BspSrfCrvFromSrf(Srf, u, CAGD_CONST_U_DIR);
  136.  
  137.     for (j = 0; j < FineNessV; j++, PtMeshPtr++) {
  138.         v = VMin + (VMax - VMin) * j / ((CagdRType) FineNessV1);
  139.         Pt = BspCrvEvalAtParam(Crv, v);
  140.         CagdCoerceToE3(PtMeshPtr -> Pt, &Pt, -1, PType);
  141.  
  142.         if (ComputeUV) {
  143.         UVMeshPtr -> UV[0] = u;
  144.         UVMeshPtr -> UV[1] = v;
  145.         UVMeshPtr++;
  146.         }
  147.     }
  148.  
  149.     CagdCrvFree(Crv);
  150.     }
  151.  
  152.     if (ComputeNormals)
  153.     PtNrml = BspSrfMeshNormals(Srf, FineNessU, FineNessV);
  154.  
  155.     /* Now that we have the mesh, create the polygons. */
  156.     for (i = 0; i < FineNessU1; i++)
  157.     for (j = 0; j < FineNessV1; j++) {
  158.         BaseIndex = i * FineNessV + j;
  159.         Pt1 = &PtMesh[BaseIndex];        /* Cache the four flat corners. */
  160.         Pt2 = &PtMesh[BaseIndex + 1];
  161.         Pt3 = &PtMesh[BaseIndex + FineNessV + 1];
  162.         Pt4 = &PtMesh[BaseIndex + FineNessV];
  163.  
  164.         if (ComputeNormals) {
  165.         Nl1 = &PtNrml[BaseIndex];
  166.         Nl2 = &PtNrml[BaseIndex + 1];
  167.         Nl3 = &PtNrml[BaseIndex + FineNessV + 1];
  168.         Nl4 = &PtNrml[BaseIndex + FineNessV];
  169.         }
  170.  
  171.         if (ComputeUV) {
  172.         UV1 = &UVMesh[BaseIndex];
  173.         UV2 = &UVMesh[BaseIndex + 1];
  174.         UV3 = &UVMesh[BaseIndex + FineNessV + 1];
  175.         UV4 = &UVMesh[BaseIndex + FineNessV];
  176.         }
  177.  
  178.         if (FourPerFlat) {  /* Eval middle point and create 4 triangles. */
  179.         CAGD_COPY_POINT(PtCenter, *Pt1);
  180.         CAGD_ADD_POINT(PtCenter, *Pt2);
  181.         CAGD_ADD_POINT(PtCenter, *Pt3);
  182.         CAGD_ADD_POINT(PtCenter, *Pt4);
  183.         CAGD_MULT_POINT(PtCenter, 0.25);
  184.  
  185.         if (ComputeNormals) {
  186.             /* Average the four normals to find the middle one. */
  187.             CAGD_COPY_VECTOR(NlCenter, *Nl1);
  188.             CAGD_ADD_VECTOR(NlCenter, *Nl2);
  189.             CAGD_ADD_VECTOR(NlCenter, *Nl3);
  190.             CAGD_ADD_VECTOR(NlCenter, *Nl4);
  191.             CAGD_NORMALIZE_VECTOR(NlCenter);
  192.         }
  193.  
  194.         if (ComputeUV) {
  195.             UVCenter.UV[0] = (UV1 -> UV[0] + UV2 -> UV[0] +
  196.                       UV3 -> UV[0] + UV4 -> UV[0]) / 4.0;
  197.             UVCenter.UV[1] = (UV1 -> UV[1] + UV2 -> UV[1] +
  198.                       UV3 -> UV[1] + UV4 -> UV[1]) / 4.0;
  199.         }
  200.  
  201.         Poly = _CagdMakePolygon(ComputeNormals, ComputeUV,
  202.                     Pt1, Pt2, &PtCenter,
  203.                     Nl1, Nl2, &NlCenter,
  204.                     UV1, UV2, &UVCenter);
  205.         CAGD_LIST_PUSH(Poly, PolyHead);
  206.         Poly = _CagdMakePolygon(ComputeNormals, ComputeUV,
  207.                     Pt2, Pt3, &PtCenter,
  208.                     Nl2, Nl3, &NlCenter,
  209.                     UV2, UV3, &UVCenter);
  210.         CAGD_LIST_PUSH(Poly, PolyHead);
  211.         Poly = _CagdMakePolygon(ComputeNormals, ComputeUV,
  212.                     Pt3, Pt4, &PtCenter,
  213.                     Nl3, Nl4, &NlCenter,
  214.                     UV3, UV4, &UVCenter);
  215.         CAGD_LIST_PUSH(Poly, PolyHead);
  216.         Poly = _CagdMakePolygon(ComputeNormals, ComputeUV,
  217.                     Pt4, Pt1, &PtCenter,
  218.                     Nl4, Nl1, &NlCenter,
  219.                     UV4, UV1, &UVCenter);
  220.         CAGD_LIST_PUSH(Poly, PolyHead);
  221.         }
  222.         else {               /* Only two along the diagonal... */
  223.         Poly = _CagdMakePolygon(ComputeNormals, ComputeUV,
  224.                     Pt1, Pt2, Pt3,
  225.                     Nl1, Nl2, Nl3,
  226.                     UV1, UV2, UV3);
  227.         CAGD_LIST_PUSH(Poly, PolyHead);
  228.         Poly = _CagdMakePolygon(ComputeNormals, ComputeUV,
  229.                     Pt3, Pt4, Pt1,
  230.                     Nl3, Nl4, Nl1,
  231.                     UV3, UV4, UV1);
  232.         CAGD_LIST_PUSH(Poly, PolyHead);
  233.         }
  234.     }
  235.  
  236.     IritFree((VoidPtr) PtMesh);
  237.     if (ComputeNormals)
  238.     IritFree((VoidPtr) PtNrml);
  239.     if (ComputeUV)
  240.     IritFree((VoidPtr) UVMesh);
  241.  
  242.     return PolyHead;
  243. }
  244.  
  245. /*****************************************************************************
  246. * Routine to convert a single bspline surface to NumOfIsolines polylines list*
  247. * in each param. direction with SamplesPerCurve in each isoparametric curve. *
  248. * Polyline are always E3 of CagdPolylineStruct type.                 *
  249. * Iso parametric curves are sampled equally spaced in parametric space.         *
  250. * NULL is returned in case of an error, otherwise list of CagdPolylineStruct.*
  251. * Attempt is made to extract isolines along C1 discontinuities first.         *
  252. *****************************************************************************/
  253. CagdPolylineStruct *BspSrf2Polylines(CagdSrfStruct *Srf, int NumOfIsocurves[2],
  254.                              int SamplesPerCurve)
  255. {
  256.     int i, NumC1Disconts, NumOfIsos, IsRegion,
  257.     n = 1 << SamplesPerCurve,
  258.     ULength = Srf -> ULength,
  259.     VLength = Srf -> VLength,
  260.     UOrder = Srf -> UOrder,
  261.     VOrder = Srf -> VOrder;
  262.     CagdRType u, v, UMin, UMax, VMin, VMax, *C1Disconts, *IsoParams, *RefKV,
  263.     *UKV = Srf -> UKnotVector,
  264.     *VKV = Srf -> VKnotVector;
  265.     CagdCrvStruct *Crv;
  266.     CagdPolylineStruct *Poly,
  267.     *PolyList = NULL;
  268.     BspKnotAlphaCoeffType *A;
  269.  
  270.     if (!CAGD_IS_BSPLINE_SRF(Srf))
  271.     return NULL;
  272.  
  273.     /* Make sure the curve is open. We move 2 Epsilons to make sure region  */
  274.     /* extraction will occur. Otherwise the curve will be copied as is.     */
  275.     if (!BspKnotHasOpenEC(UKV, ULength, UOrder) ||
  276.     !BspKnotHasOpenEC(VKV, VLength, VOrder)) {
  277.     CagdSrfStruct
  278.         *TSrf = CagdSrfRegionFromSrf(Srf,
  279.                      UKV[UOrder - 1] + EPSILON * 2,
  280.                      UKV[ULength] - EPSILON * 2,
  281.                      CAGD_CONST_U_DIR);
  282.  
  283.     Srf = CagdSrfRegionFromSrf(TSrf,
  284.                    VKV[VOrder - 1] + EPSILON * 2,
  285.                    VKV[VLength] - EPSILON * 2,
  286.                    CAGD_CONST_V_DIR);
  287.  
  288.     CagdSrfFree(TSrf);
  289.  
  290.     IsRegion = TRUE;
  291.     }
  292.     else
  293.     IsRegion = FALSE;
  294.  
  295.     /* Make sure requested format is something reasonable. */
  296.     if (SamplesPerCurve < 1)
  297.     SamplesPerCurve = 1;
  298.     if (SamplesPerCurve > CAGD_MAX_BEZIER_CACHE_ORDER)
  299.     SamplesPerCurve = CAGD_MAX_BEZIER_CACHE_ORDER;
  300.     if (NumOfIsocurves[0] < 2)
  301.     NumOfIsocurves[0] = 2;
  302.     if (NumOfIsocurves[1] <= 0)
  303.     NumOfIsocurves[1] = NumOfIsocurves[0];
  304.     else if (NumOfIsocurves[1] < 2)
  305.     NumOfIsocurves[1] = 2;
  306.  
  307.     BspSrfDomain(Srf, &UMin, &UMax, &VMin, &VMax);
  308.  
  309.     /* Compute discontinuities along the u axis and use that to determine    */
  310.     /* where to extract isolines along u.                     */
  311.     /* Note C1Disconts is freed by BspKnotParamValues.                 */
  312.  
  313.     /* Add heuristically more samples if surface has interior knots.         */
  314.     NumOfIsos = NumOfIsocurves[0];
  315.     if (UOrder > 2)
  316.     NumOfIsos += (ULength - UOrder) / 2;
  317.  
  318.     C1Disconts = BspKnotAllC1Discont(Srf -> UKnotVector, UOrder,
  319.                      ULength, &NumC1Disconts);
  320.     IsoParams = BspKnotParamValues(UMin, UMax, NumOfIsos, C1Disconts,
  321.                                 NumC1Disconts);
  322.     RefKV = BspKnotPrepEquallySpaced(MAX(n - VLength, 1),
  323.                      VMin, VMax);
  324.     A = BspKnotEvalAlphaCoefMerge(VOrder, Srf -> VKnotVector, VLength, RefKV,
  325.                   MAX(n - VLength, 1));
  326.     IritFree((VoidPtr) RefKV);
  327.  
  328.     for (i = 0; i < NumOfIsos; i++) {
  329.     u = IsoParams[i];
  330.  
  331.     Crv = BspSrfCrvFromSrf(Srf, u, CAGD_CONST_U_DIR);
  332.     Poly = BspCrv2Polyline(Crv, SamplesPerCurve, A);
  333.     Poly -> Pnext = PolyList;
  334.     PolyList = Poly;
  335.     CagdCrvFree(Crv);
  336.     }
  337.     IritFree((VoidPtr) IsoParams);
  338.     BspKnotFreeAlphaCoef(A);
  339.  
  340.     /* Compute discontinuities along the v axis and use that to determine    */
  341.     /* where to extract isolines along v.                     */
  342.     /* Note C1Disconts is freed by BspKnotParamValues.                 */
  343.  
  344.     /* Add heuristically more samples if surface has interior knots.         */
  345.     NumOfIsos = NumOfIsocurves[1];
  346.     if (VOrder > 2)
  347.     NumOfIsos += (VLength - VOrder) / 2;
  348.  
  349.     C1Disconts = BspKnotAllC1Discont(Srf -> VKnotVector, VOrder,
  350.                      VLength, &NumC1Disconts);
  351.     IsoParams = BspKnotParamValues(VMin, VMax, NumOfIsos, C1Disconts,
  352.                                 NumC1Disconts);
  353.     RefKV = BspKnotPrepEquallySpaced(MAX(n - ULength, 1),
  354.                      UMin, UMax);
  355.     A = BspKnotEvalAlphaCoefMerge(UOrder, Srf -> UKnotVector, ULength, RefKV,
  356.                   MAX(n - ULength, 1));
  357.     IritFree((VoidPtr) RefKV);
  358.  
  359.     for (i = 0; i < NumOfIsos; i++) {
  360.     v = IsoParams[i];
  361.  
  362.     Crv = BspSrfCrvFromSrf(Srf, v, CAGD_CONST_V_DIR);
  363.     Poly = BspCrv2Polyline(Crv, SamplesPerCurve, A);
  364.     Poly -> Pnext = PolyList;
  365.     PolyList = Poly;
  366.     CagdCrvFree(Crv);
  367.     }
  368.     IritFree((VoidPtr) IsoParams);
  369.     BspKnotFreeAlphaCoef(A);
  370.  
  371.     return PolyList;
  372. }
  373.  
  374. /*****************************************************************************
  375. * Routine to convert a single bspline surface to NumOfIsoline isocurve list  *
  376. * in each param. direction.                             *
  377. * Iso parametric curves are sampled equally spaced in parametric space.         *
  378. * NULL is returned in case of an error, otherwise list of CagdCrvStruct.     *
  379. *****************************************************************************/
  380. CagdCrvStruct *BspSrf2Curves(CagdSrfStruct *Srf, int NumOfIsocurves[2])
  381. {
  382.     int i, NumC1Disconts,
  383.     ULength = Srf -> ULength,
  384.     VLength = Srf -> VLength,
  385.     UOrder = Srf -> UOrder,
  386.     VOrder = Srf -> VOrder;
  387.     CagdRType u, v, UMin, UMax, VMin, VMax, *C1Disconts, *IsoParams;
  388.     CagdCrvStruct *Crv,
  389.     *CrvList = NULL;
  390.  
  391.     if (!CAGD_IS_BSPLINE_SRF(Srf))
  392.     return NULL;
  393.  
  394.     /* Make sure requested format is something reasonable. */
  395.     if (NumOfIsocurves[0] < 2)
  396.     NumOfIsocurves[0] = 2;
  397.     if (NumOfIsocurves[1] <= 0)
  398.     NumOfIsocurves[1] = NumOfIsocurves[0];
  399.     else if (NumOfIsocurves[1] < 2)
  400.     NumOfIsocurves[1] = 2;
  401.  
  402.     BspSrfDomain(Srf, &UMin, &UMax, &VMin, &VMax);
  403.  
  404.     /* Compute discontinuities along the u axis and use that to determine    */
  405.     /* where to extract isolines along u.                     */
  406.     /* Note C1Disconts is freed by BspKnotParamValues.                 */
  407.     C1Disconts = BspKnotAllC1Discont(Srf -> UKnotVector, UOrder,
  408.                      ULength, &NumC1Disconts);
  409.     IsoParams = BspKnotParamValues(UMin, UMax, NumOfIsocurves[0], C1Disconts,
  410.                                 NumC1Disconts);
  411.  
  412.     for (i = 0; i < NumOfIsocurves[0]; i++) {
  413.     u = IsoParams[i];
  414.  
  415.     Crv = BspSrfCrvFromSrf(Srf, u, CAGD_CONST_U_DIR);
  416.     Crv -> Pnext = CrvList;
  417.     CrvList = Crv;
  418.     }
  419.     IritFree((VoidPtr) IsoParams);
  420.  
  421.     /* Compute discontinuities along the v axis and use that to determine    */
  422.     /* where to extract isolines along v.                     */
  423.     /* Note C1Disconts is freed by BspKnotParamValues.                 */
  424.     C1Disconts = BspKnotAllC1Discont(Srf -> VKnotVector, VOrder,
  425.                      VLength, &NumC1Disconts);
  426.     IsoParams = BspKnotParamValues(VMin, VMax, NumOfIsocurves[1], C1Disconts,
  427.                                 NumC1Disconts);
  428.  
  429.     for (i = 0; i < NumOfIsocurves[1]; i++) {
  430.     v = IsoParams[i];
  431.  
  432.     Crv = BspSrfCrvFromSrf(Srf, v, CAGD_CONST_V_DIR);
  433.     Crv -> Pnext = CrvList;
  434.     CrvList = Crv;
  435.     }
  436.     IritFree((VoidPtr) IsoParams);
  437.  
  438.     return CrvList;
  439. }
  440.  
  441. /*****************************************************************************
  442. * Routine to approx. a single bspline curve as a polyline with             *
  443. * 2^SamplesPerCurve samples. Polyline is always E3 CagdPolylineStruct type.  *
  444. * Curve is refined equally spaced in parametric space, unless the curve is   *
  445. * linear in which the control polygon is simply being copied.             *
  446. * If A is specified, it is used to refine the curve.                 *
  447. * NULL is returned in case of an error, otherwise CagdPolylineStruct.         *
  448. *****************************************************************************/
  449. CagdPolylineStruct *BspCrv2Polyline(CagdCrvStruct *Crv, int SamplesPerCurve,
  450.                              BspKnotAlphaCoeffType *A)
  451. {
  452.     int i, j, n, IsRegion,
  453.     Order = Crv -> Order,
  454.     Len = Crv -> Length,
  455.     IsNotRational = !CAGD_IS_RATIONAL_CRV(Crv),
  456.     MaxCoord = CAGD_NUM_OF_PT_COORD(Crv -> PType);
  457.     CagdRType *Polyline[CAGD_MAX_PT_SIZE], Scaler,
  458.     *KV = Crv -> KnotVector;
  459.     CagdPtStruct *NewPolyline;
  460.     CagdPolylineStruct *P;
  461.  
  462.     if (!CAGD_IS_BSPLINE_CRV(Crv))
  463.     return NULL;
  464.  
  465.     /* Make sure the curve is open. We move 2 Epsilons to make sure region  */
  466.     /* extraction will occur. Otherwise the curve will be copied as is.     */
  467.     if (!BspKnotHasOpenEC(KV, Len, Order)) {
  468.     Crv = CagdCrvRegionFromCrv(Crv, KV[Order - 1] + EPSILON * 2,
  469.                         KV[Len] - EPSILON * 2);
  470.     IsRegion = TRUE;
  471.     }
  472.     else
  473.     IsRegion = FALSE;
  474.  
  475.     /* Make sure requested format is something reasonable. */
  476.     if (SamplesPerCurve < 1)
  477.     SamplesPerCurve = 1;
  478.  
  479.     if ((1 << SamplesPerCurve) <= Crv -> Length) {
  480.         /* Make sure 2^SamplesPerCurve can hold the entire control polygon. */
  481.         for (i = 1, SamplesPerCurve = 0;
  482.          i <= Crv -> Length;
  483.          i <<= 1, SamplesPerCurve++);
  484.     }
  485.  
  486.     n = MAX(A ? A -> RefLength : 0, 1 << SamplesPerCurve);
  487.  
  488.     P = CagdPolylineNew(n);
  489.     NewPolyline = P -> Polyline;
  490.  
  491.     /* Allocate temporary memory to hold evaluated curve. */
  492.     for (i = 0; i < CAGD_MAX_PT_SIZE; i++)
  493.     Polyline[i] = (CagdRType *) IritMalloc(sizeof(CagdRType) * n);
  494.  
  495.     if (MaxCoord > 3)
  496.     MaxCoord = 3;
  497.  
  498.     n = P -> Length = CagdCrvEvalToPolyline(Crv,
  499.                         A == NULL ? SamplesPerCurve : 0,
  500.                         Polyline, A);
  501.  
  502.     for (i = n - 1; i >= 0; i--) {              /* Convert to E3 polyline. */
  503.     if (IsNotRational)
  504.         Scaler = 1.0;
  505.     else
  506.         Scaler = Polyline[0][i];
  507.  
  508.     for (j = 0; j < MaxCoord; j++)
  509.        NewPolyline[i].Pt[j] = Polyline[j+1][i] / Scaler;
  510.     for (j = MaxCoord; j < 3; j++)
  511.        NewPolyline[i].Pt[j] = 0.0;
  512.     }
  513.     for (i = 0; i < CAGD_MAX_PT_SIZE; i++)
  514.     IritFree((VoidPtr) Polyline[i]);
  515.  
  516.     if (IsRegion)
  517.     CagdCrvFree(Crv);
  518.  
  519.     return P;
  520. }
  521.